#!/usr/bin/env python3
import os
import subprocess
import sys
import platform
import shutil
from pathlib import Path
import json


class Vue3TsViteFullExample:
    def __init__(self):
        self.project_name = ""
        self.port = 3000
        self.need_proxy = False
        self.proxy_config = {}
        self.project_dir = ""
        self.npm_cmd = "npm.cmd" if platform.system() == "Windows" else "npm"

        self.optional_modules = {
            "1": {"name": "Vue Router", "packages": ["vue-router@4"], "selected": False},
            "2": {"name": "Pinia", "packages": ["pinia"], "selected": False},
            "3": {"name": "ESLint + Prettier", "packages": ["eslint", "eslint-plugin-vue", "prettier"],
                  "selected": False},
            "4": {"name": "Axios", "packages": ["axios"], "selected": False},
            "5": {"name": "VueUse", "packages": ["@vueuse/core"], "selected": False},
            "6": {"name": "Tailwind CSS", "packages": ["tailwindcss", "postcss", "autoprefixer"], "selected": False},
            "7": {
                "name": "Element Plus",
                "packages": ["element-plus", "unplugin-vue-components", "unplugin-auto-import"],
                "selected": False
            }
        }

    def run(self):
        self.collect_user_input()
        self.ask_optional_modules()
        self.create_project()
        self.install_dependencies()
        self.configure_vite()
        self.generate_examples()
        self.optional_module_config()
        self.print_success()

    def collect_user_input(self):
        self.project_name = input("📁 项目名称: ").strip()
        if not self.project_name:
            print("❌ 项目名称不能为空")
            sys.exit(1)

        port = input("🌐 开发端口（默认 3000）: ").strip()
        if port:
            try:
                self.port = int(port)
            except ValueError:
                print("❌ 端口号必须是数字")
                sys.exit(1)

        proxy = input("🌍 是否配置代理？(y/n): ").strip().lower()
        self.need_proxy = proxy == 'y'
        if self.need_proxy:
            self.configure_proxy()

    def ask_optional_modules(self):
        print("📦 选择需要的模块（如 1,2,4）:")
        for key, mod in self.optional_modules.items():
            print(f"[{key}] {mod['name']}")
        selection = input("输入模块编号: ").strip()
        for key in selection.split(","):
            if key.strip() in self.optional_modules:
                self.optional_modules[key.strip()]["selected"] = True

    def configure_proxy(self):
        print("🌐 配置代理（输入为空跳出）:")
        while True:
            prefix = input("请输入代理前缀（如 /api）: ").strip()
            if not prefix:
                break
            target = input(f"请输入 {prefix} 对应地址（如 http://localhost:8080）: ").strip()
            if not target:
                print("❌ 目标地址不能为空")
                continue
            # 使用 re.escape 处理正则表达式转义
            import re
            escaped_prefix = re.escape(prefix)
            self.proxy_config[prefix] = {
                "target": target,
                "changeOrigin": True,
                "rewrite": f"(path) => path.replace(/^{escaped_prefix}/, '')"
            }

    def create_project(self):
        print("📁 创建项目...")
        try:
            # 添加 --silent 参数禁用警告
            subprocess.run(
                [self.npm_cmd, "create", "vite@latest", self.project_name, "--", "--template", "vue-ts", "--silent"],
                check=True)
            self.project_dir = str(Path.cwd() / self.project_name)
        except subprocess.CalledProcessError as e:
            print("❌ 项目创建失败:", e)
            sys.exit(1)

    def install_dependencies(self):
        print("📦 安装依赖...")
        os.chdir(self.project_dir)
        self.safe_install(["install"])
        # 安装 Vite Vue 插件锁定版本（可根据需要调整）
        self.safe_install(["install", "--save-dev", "vite@4.5.0", "@vitejs/plugin-vue@4.5.0"])
        for mod in self.optional_modules.values():
            if mod["selected"]:
                self.safe_install(["install"] + mod["packages"])

    def configure_vite(self):
        print("⚙️ 配置 Vite...")
        config = Path("vite.config.ts")
        if not config.exists():
            print("❗ 未找到 vite.config.ts，跳过")
            return

        proxy_code = ""
        if self.need_proxy and self.proxy_config:
            proxy_str = json.dumps(self.proxy_config, indent=4)
            proxy_str = proxy_str.replace('"rewrite": "', 'rewrite: ').replace('")"', ')').replace("\\\\", "\\")
            proxy_str = proxy_str.replace('path.replace(/\\^', 'path.replace(/^')
            proxy_code = f"    proxy: {proxy_str},\n"

        content = f"""import {{ defineConfig }} from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({{
  plugins: [vue()],
  server: {{
    port: {self.port},
    open: true,
{proxy_code}  }}
}})
"""
        config.write_text(content, encoding="utf-8")

    def generate_examples(self):
        # 生成 App.vue
        self.create_app_vue()

        # main.ts 根据选项注入代码
        self.create_main_ts()

        # 路由示例
        if self.optional_modules["1"]["selected"]:
            self.create_router_example()

        # Pinia 示例
        if self.optional_modules["2"]["selected"]:
            self.create_pinia_example()

        # Axios 示例
        if self.optional_modules["4"]["selected"]:
            self.create_axios_example()

        # Tailwind 示例（样式文件自动创建和引入在optional_module_config）

    def create_app_vue(self):
        app_vue_content = """<template>
  <div class="app">
    <h1>欢迎使用 Vite + Vue 3 + TypeScript + 智能脚手架</h1>
    <router-view v-if="$router" />
    <p v-else>未启用路由</p >
    <Counter v-if="showCounter" />
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const showCounter = ref(true)
</script>

<style scoped>
.app {
  text-align: center;
  margin-top: 30px;
}
</style>
"""
        Path("src/App.vue").write_text(app_vue_content, encoding="utf-8")

        # 如果启用了 Pinia，自动生成一个 Counter 组件示例
        if self.optional_modules["2"]["selected"]:
            os.makedirs("src/components", exist_ok=True)
            counter_vue = """<template>
  <div>
    <h2>Counter 计数器</h2>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <p>Count: {{ count }}</p >
  </div>
</template>

<script lang="ts" setup>
import { useCounterStore } from '../stores/counter'
import { storeToRefs } from 'pinia'

const counter = useCounterStore()
const { count } = storeToRefs(counter)

function increment() {
  counter.increment()
}

function decrement() {
  counter.decrement()
}
</script>
"""
            Path("src/components/Counter.vue").write_text(counter_vue, encoding="utf-8")

            # 生成 Pinia store 示例
            os.makedirs("src/stores", exist_ok=True)
            counter_store = """import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  }
})
"""
            Path("src/stores/counter.ts").write_text(counter_store, encoding="utf-8")

    def create_main_ts(self):
        main_ts_path = Path("src/main.ts")
        lines = [
            "import { createApp } from 'vue'",
            "import App from './App.vue'"
        ]

        if self.optional_modules["1"]["selected"]:
            lines.append("import router from './router'")
        if self.optional_modules["2"]["selected"]:
            lines.append("import { createPinia } from 'pinia'")
        if self.optional_modules["6"]["selected"]:
            lines.append("import './index.css'")

        lines.append("import Counter from './components/Counter.vue'")

        lines.append("")
        lines.append("const app = createApp(App)")

        if self.optional_modules["2"]["selected"]:
            lines.append("const pinia = createPinia()")
            lines.append("app.use(pinia)")
        if self.optional_modules["1"]["selected"]:
            lines.append("app.use(router)")

        lines.append("app.mount('#app')")

        main_ts_path.write_text("\n".join(lines), encoding="utf-8")

    def create_router_example(self):
        os.makedirs("src/router", exist_ok=True)
        router_index = """import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router
"""
        Path("src/router/index.ts").write_text(router_index, encoding="utf-8")

        # 创建 Home.vue 页面
        os.makedirs("src/components", exist_ok=True)
        home_vue = """<template>
  <div>
    <h2>首页</h2>
    <p>这是路由示例的首页组件。</p >
  </div>
</template>

<script lang="ts" setup>
</script>
"""
        Path("src/components/Home.vue").write_text(home_vue, encoding="utf-8")

    def create_pinia_example(self):
        # Pinia store 已在 create_app_vue 中生成示例了，这里确认 stores 文件夹已创建
        Path("src/stores").mkdir(exist_ok=True)

    def create_axios_example(self):
        os.makedirs("src/utils", exist_ok=True)
        axios_util = """import axios from 'axios'

const instance = axios.create({
  baseURL: '/api',
  timeout: 5000
})

// 请求拦截器
instance.interceptors.request.use(config => {
  // 可添加token
  return config
})

// 响应拦截器
instance.interceptors.response.use(response => {
  return response.data
}, error => {
  return Promise.reject(error)
})

export default instance
"""
        Path("src/utils/axios.ts").write_text(axios_util, encoding="utf-8")

        # 在 Home.vue 添加示例调用
        home_path = Path("src/components/Home.vue")
        if home_path.exists():
            content = home_path.read_text(encoding="utf-8")
            if "axios" not in content:
                content = content.replace(
                    "</script>",
                    """import axios from '../utils/axios'

async function fetchData() {
  try {
    const res = await axios.get('/test')
    console.log('API 响应:', res)
  } catch (e) {
    console.error(e)
  }
}

fetchData()
</script>"""
                )
                home_path.write_text(content, encoding="utf-8")

    def optional_module_config(self):
        if self.optional_modules["3"]["selected"]:
            Path(".prettierrc").write_text(json.dumps({
                "semi": True, "singleQuote": True, "tabWidth": 2
            }, indent=2), encoding="utf-8")

        if self.optional_modules["6"]["selected"]:
            print("🎨 初始化 Tailwind CSS")
            try:
                # 添加 --silent 参数禁用警告
                subprocess.run(["npx", "tailwindcss", "init", "-p", "--silent"], check=True)
            except Exception as e:
                print("❌ tailwind init 失败，请手动运行: npx tailwindcss init -p")

            Path("src/index.css").write_text("""@tailwind base;
@tailwind components;
@tailwind utilities;
""", encoding="utf-8")

            main_ts = Path("src/main.ts")
            lines = main_ts.read_text(encoding="utf-8").splitlines()
            if not any("index.css" in line for line in lines):
                lines.insert(1, "import './index.css'")
                main_ts.write_text("\n".join(lines), encoding="utf-8")

        if self.optional_modules["7"]["selected"]:
            print("✨ 配置 Element Plus 插件")
            # 更新 vite.config.ts 添加插件引入
            config_path = Path("vite.config.ts")
            if config_path.exists():
                vite_content = config_path.read_text(encoding="utf-8")
                if "unplugin-vue-components" not in vite_content:
                    lines = vite_content.splitlines()
                    for i, line in enumerate(lines):
                        if line.strip().startswith("plugins:"):
                            lines[i] = line.replace("vue()", "vue(),\n    Components({}),\n    AutoImport({})")
                            break
                    imports = """import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'"""
                    vite_content = imports + "\n" + "\n".join(lines)
                    config_path.write_text(vite_content, encoding="utf-8")

            # 在 main.ts 自动注入 element-plus 样式
            main_ts_path = Path("src/main.ts")
            if main_ts_path.exists():
                content = main_ts_path.read_text(encoding="utf-8")
                if "element-plus/dist/index.css" not in content:
                    lines = content.splitlines()
                    lines.insert(1, "import 'element-plus/dist/index.css'")
                    main_ts_path.write_text("\n".join(lines), encoding="utf-8")

    def safe_install(self, args, cwd=None):
        # 添加 --silent 参数禁用 npm 警告
        npm_args = [self.npm_cmd] + args + ["--silent"]
        pnpm_args = ["pnpm"] + args

        try:
            print(f"🟢 安装: {' '.join(args)}")
            subprocess.run(npm_args, check=True, cwd=cwd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError:
            try:
                print(f"⚠️ npm 安装失败，尝试 pnpm: {' '.join(args)}")
                subprocess.run(pnpm_args, check=True, cwd=cwd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
            except Exception:
                print("❌ 依赖安装失败，请检查网络或 pnpm 是否安装")
                sys.exit(1)

    def print_success(self):
        print(f"\n✅ 项目已生成：cd {self.project_name}")
        print("🚀 启动开发服务器：npm run dev 或 pnpm run dev")


if __name__ == "__main__":
    Vue3TsViteFullExample().run()